﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace pwestcott.Util.Tests.Essence
{
    [TestFixture]
    public class GetHashCodeTest
    {
        [EssenceClass(UseIn = EssenceFunctions.All)]
        class TestEssence
        {
            [Essence(Order = 0)] public int MyInt;
            [Essence(Order = 1)] public string MyString;
            [Essence(Order = 2)] public DateTime MyDateTime;

            public override int GetHashCode()
            {
                return Essence<TestEssence>.GetHashCodeStatic(this);
            }
        }

        class TestManual
        {
            public int MyInt;
            public string MyString;
            public DateTime MyDateTime;

            public override int GetHashCode()
            {
                var x = MyInt.GetHashCode();
                x *= Essence<TestEssence>.HashCodeMultiplier;
                x ^= (MyString == null) ? 0 : MyString.GetHashCode();
                x *= Essence<TestEssence>.HashCodeMultiplier;
                x ^= MyDateTime.GetHashCode();
                return x;
            }
        }

        //class EssenceMemberTest
        //{
        //    private readonly Func<int> getHashCode;

        //    [Essence(Order = 0)] public int MyInt;
        //    [Essence(Order = 1)] public string MyString;
        //    [Essence(Order = 2)] public DateTime MyDateTime;

        //    EssenceMemberTest()
        //    {
        //        getHashCode = Essence<EssenceMemberTest>.GetHashCodeInstance(this);
        //    }

        //    public override int GetHashCode()
        //    {
        //        return getHashCode();
        //    }
        //}

        [Test]
        public void DefaultValues()
        {
            var m = new TestManual();
            var e = new TestEssence();

            Assert.AreEqual(e.GetHashCode(), m.GetHashCode());
        }

        [Test]
        public void RandomInt()
        {
            var m = new TestManual();
            var e = new TestEssence();

            Random r = new Random();
            m.MyInt = e.MyInt = r.Next();

            Assert.AreEqual(e.GetHashCode(), m.GetHashCode());
        }

        [Test]
        public void DifferentInt()
        {
            var m = new TestManual();
            var e = new TestEssence();

            m.MyInt = 0;
            e.MyInt = 1;

            Assert.AreNotEqual(e.GetHashCode(), m.GetHashCode());
        }

        [Test]
        public void TodaysDate()
        {
            var m = new TestManual();
            var e = new TestEssence();

            m.MyDateTime = e.MyDateTime = DateTime.Now;

            Assert.AreEqual(e.GetHashCode(), m.GetHashCode());
        }

        [Test]
        public void DifferentDate()
        {
            var m = new TestManual();
            var e = new TestEssence();

            m.MyDateTime = new DateTime(2009, 03, 17);
            e.MyDateTime = new DateTime(2009, 03, 18);

            // Not _really_ guaranteed to be different; but unless they change the algorithm of GetHashCode
            // of a DateTime object, then we're pretty safe
            Assert.AreNotEqual(e.GetHashCode(), m.GetHashCode());
        }

        [Test]
        public void TheQuickBrownFox()
        {
            var m = new TestManual();
            var e = new TestEssence();

            m.MyString = e.MyString = "The quick brown fox jumps over the lazy dog";

            Assert.AreEqual(e.GetHashCode(), m.GetHashCode());
        }

        [Test]
        public void DifferentStrings()
        {
            var m = new TestManual();
            var e = new TestEssence();

            m.MyString = null;
            e.MyString = "The quick brown fox jumps over the lazy dog";

            Assert.AreNotEqual(e.GetHashCode(), m.GetHashCode());
        }
    }
}
